/*
 * $Id: WebUtilities.java 42 2013-04-17 15:33:59Z gabakyan $
 * $Author: gabakyan $
 * $Revision: 42 $
 * $Date: 2013-04-17 15:33:59 +0000 (Wed, 17 Apr 2013) $
 *
 * Copyright (c) 2013 Supply Chain Intelligence (SCI), Inc.
 * http://www.scintelligence.com/, Email: info@scintelligence.com
 * All rights reserved.
 *
 * This file is part of Logistics Map.
 *
 * Logistics Map is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Logistics Map is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Logistics Map.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sci.logisticsmap.web.support;

import com.sci.logisticsmap.support.Constants;
import com.sci.logisticsmap.support.model.UserLogType;
import com.sci.logisticsmap.support.model.UserStatus;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;

/**
 * The utility class which provides helper methods.
 *
 * @author gabakyan@gmail.com (Last modified by $Author: gabakyan $)
 * @version $Revision: 42 $
 */
public final class WebUtilities {
    /**
     * The country code select options.
     */
    private static final List<SelectOption<String>> countryCodeSelectOptions;
    /**
     * The user status select options.
     */
    private static final List<SelectOption<String>> userStatusSelectOptions;
    /**
     * The user log type to message codes map.
     */
    private static final Map<UserLogType, String> userLogTypeToMessageCodes;

    /**
     * The static initialization block.
     */
    static {
		countryCodeSelectOptions = new ArrayList<SelectOption<String>>();
        for (String countryCode : Constants.COUNTRY_CODES) {
            /*if (countryCode.equals(Constants.COUNTRY_CODE_UNKNOWN)) {
                continue;
            }*/
            countryCodeSelectOptions.add(new SelectOption<String>(countryCode, "common.country.".concat(countryCode)));
        }

		userStatusSelectOptions = new ArrayList<SelectOption<String>>();
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.NEW_INCOMPLETE, "common.userStatus.newIncomplete"));
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.NEW, "common.userStatus.new"));
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.VERIFIED_INCOMPLETE, "common.userStatus.verifiedIncomplete"));
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.VERIFIED, "common.userStatus.verified"));
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.APPROVED, "common.userStatus.approved"));
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.REJECTED, "common.userStatus.rejected"));
		userStatusSelectOptions.add(new SelectOption<String>(UserStatus.BLOCKED, "common.userStatus.blocked"));

		userLogTypeToMessageCodes = new HashMap<UserLogType, String>();
		userLogTypeToMessageCodes.put(UserLogType.SIGN_IN, "common.userLogType.signIn");
		userLogTypeToMessageCodes.put(UserLogType.SIGN_OUT, "common.userLogType.signOut");
		userLogTypeToMessageCodes.put(UserLogType.SIGN_UP, "common.userLogType.signUp");
		userLogTypeToMessageCodes.put(UserLogType.SESSION_DESTROYED, "common.userLogType.sessionDestroyed");
    }

    /**
     * The private constructor.
     */
    private WebUtilities() {
    }

    /**
     * Returns the client IP address.
     *
     * @param request The http servlet request.
     *
     * @return The client IP address.
     */
    public static String getClientIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");  
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * Forwards the given request.
     *
     * @param request the http servlet request.
     * @param response the http servlet response.
     * @param path the path.
     *
     * @exception ServletException if the target resource throws this exception.
     * @exception IOException if the target resource throws this exception.
     */
    public static void forwardRequest(HttpServletRequest request, HttpServletResponse response, String path)
            throws ServletException, IOException {
        request.getRequestDispatcher(path).forward(request, response);
    }

    /**
     * Redirects the given request.
     *
     * @param request the http servlet request.
     * @param response the http servlet response.
     * @param path the path.
     *
     * @exception IOException if an input or output exception occurs.
     */
    public static void sendRedirect(HttpServletRequest request, HttpServletResponse response, String path)
            throws IOException {
        response.sendRedirect(new StringBuffer(request.getContextPath()).append(path).toString());
    }

    /**
     * Returns the country code select options.
     *
     * @return The country code select options.
     */
    public static List<SelectOption<String>> getCountryCodeSelectOptions() {
        return countryCodeSelectOptions;
    }

    /**
     * Returns the country code select options.
     *
     * @param selectedCountryCodes The selected country codes.
     *
     * @return The country code select options.
     */
    public static List<SelectOption<String>> getCountryCodeSelectOptions(String[] selectedCountryCodes) {
        return getReorderedSelectOptions(countryCodeSelectOptions, selectedCountryCodes);
    }

    /**
     * Returns the user status select options.
     *
     * @return The user status select options.
     */
    public static List<SelectOption<String>> getUserStatusSelectOptions() {
        return userStatusSelectOptions;
    }

    /**
     * Returns the user log type to message codes map.
     *
     * @return The user log type to message codes map.
     */
    public static Map<UserLogType, String> getUserLogTypeToMessageCodes() {
        return userLogTypeToMessageCodes;
    }

    /**
     * Validates the page number request parameter.
     *
     * @param page The page number request parameter.
     *
     * @return The client IP address.
     */
    public static int validatePageRequestParam(Integer page) {
        return (page != null && page > 0) ? page : 1;
    }

    /**
     * Returns the reordered select options.
     *
     * @param selectOptions The select options.
     * @param selectedValues The selected values.
     *
     * @return The reordered select options.
     */
	private static <Value extends Serializable> List<SelectOption<Value>> getReorderedSelectOptions(List<SelectOption<Value>> selectOptions, Value[] selectedValues) {
        List<SelectOption<Value>> selectedSelectOptions = new ArrayList<SelectOption<Value>>();
        List<SelectOption<Value>> newSelectOptions = new ArrayList<SelectOption<Value>>();
        for (SelectOption<Value> selectOption : selectOptions) {
            boolean selected = false;
            for (Value selectedValue : selectedValues) {
                if (selectOption.getValue().equals(selectedValue)) {
                    selected = true;
                    break;
                }
            }
            if (selected) {
                selectedSelectOptions.add(selectOption);
            } else {
                newSelectOptions.add(selectOption);
            }
        }

		selectedSelectOptions.addAll(newSelectOptions);

        return selectedSelectOptions;
    }
}
